﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using uam_fps_game.Gfx;
using uam_fps_game.Cameras;
using uam_fps_game.Utils;
using Microsoft.Xna.Framework.Content;
using uam_fps_game.NetComponents;
using uam_fps_game.Physics;

namespace uam_fps_game.Scenes
{
    public class Scene
    {
        internal FpsCamera Camera { get; private set; }

        internal SceneNode RootNode { get; private set; }

        internal List<Light> Lights { get; private set; }

        internal Terrain Terrain { get; set; }

        private GraphicsDevice _device;

        private PlayerNode _localPlayer;

        private SceneNetComp _netComp;

        internal Scene(GraphicsDevice device)
        {
            _device = device;

            Camera = new FpsCamera(new Vector3(0.0f, 5.0f, 50.0f), new Vector3(0, 0, 0), Vector3.Up,
                MathHelper.ToRadians(45.0f),
                (float)device.Viewport.Width / (float)device.Viewport.Height,
                0.1f, 1000.0f);

            RootNode = new SceneNode(this);

            Lights = new List<Light>();

            GraphicsSystem.Global.SceneData.ProjectionMatrix = Camera.Projection;

            BoundingSphereRenderer.InitializeGraphics(device, 10);

            _netComp = new SceneNetComp();
        }

        

        public void Update(float deltaTime)
        {
            CheckNetComponent();

            PhysicsSystem.Global.Update(deltaTime);

            Camera.Update(deltaTime);

            RootNode.UpdateWithChildren(deltaTime, Matrix.Identity);

            GraphicsSystem.Global.Update(deltaTime);
        }

        public void Render()
        {
            Terrain.Render(Camera.View, Camera.Projection);

            GraphicsSystem.Global.SceneData.ViewMatrix = Camera.View;
            GraphicsSystem.Global.SceneData.EyePosition = Camera.Position;

            GraphicsSystem.Global.RenderScene();

            //if (Microsoft.Xna.Framework.Input.Keyboard.GetState().IsKeyDown(Keys.B))
            //{
            //    for (int i = 0; i < RootNode.ChildNodes.Count; ++i)
            //    {
            //        BoundingSphereRenderer.Render(RootNode.ChildNodes[i].BoundingSphere, mDevice, Camera.View, Camera.Projection, Color.Blue);
            //    }
            //}
        }

        private void CheckNetComponent()
        {
            Queue<Message> msgs = _netComp.ReceivedMessages;
            while (msgs.Count > 0)
            {
                Message msg = msgs.Dequeue();
                if (msg.MessageId == 666) // Proper enum should be here instead of 666
                {
                    CreatePlayer(msg);
                }
            }
        }

        public void SendAddPlayer()
        {
            PlayerAdd msg = new PlayerAdd();
            msg.PlayerId = 0;
            _netComp.MessagesToSend.Enqueue(msg);
        }

        private void CreatePlayer(Message msg)
        {
            PlayerAdd addMsg = (PlayerAdd)msg;
            PlayerNode player = new PlayerNode(this, GraphicsSystem.Global.CreateModelInstance("Models\\Fountain"), false, true, new ClientPlayerNetComp(addMsg.PlayerId));
            player.Position = new Vector3(3600, -200, 3600);
            RootNode.ChildNodes.Add(player);
        }

        public static Scene CreateTestScene(GraphicsDevice device, ContentManager content, bool isServer)
        {
            Scene scene = new Scene(device);

            Logger.Instance.LogError("LOGGER TEST");

            GraphicsNode node;
            //for (int i = 0; i < 5; ++i)
            //{
            //    for (int j = 0; j < 5; ++j)
            //    {
            //        ModelInstance model1 = GraphicsSystem.Global.CreateModelInstance("Models\\p1_wedge");

            //        node = new GraphicsNode(scene);
            //        node.Position = new Vector3(i * 30, 28, j * 30 + 30);
            //        node.VisualObjects.Add(model1);
            //        scene.RootNode.ChildNodes.Add(node);

            //        ModelInstance model2 = GraphicsSystem.Global.CreateModelInstance("Models\\Assault Rifle");

            //        node = new GraphicsNode(scene);
            //        node.Position = new Vector3(i * 30 + 15, 0, j * 30 + 15);
            //        node.VisualObjects.Add(model2);
            //        scene.RootNode.ChildNodes.Add(node);

            //    }
            //}


            
            //ParticleSystem smokePlumeParticles = GraphicsSystem.Global.CreateParticleSystem(device);
            //GraphicsNode particlesystemn = new GraphicsNode(scene);
            //particlesystemn.Position = new Vector3(33, 5, 33);
            //particlesystemn.VisualObjects.Add(smokePlumeParticles);
            //scene.RootNode.ChildNodes.Add(particlesystemn);
            
            
            Light light = GraphicsSystem.Global.CreateLight(LightType.SPOT);
            light.SpotAngle = 66.0f;  // SpotAngle teraz przymuje kąt w stopniach.

            Billboard lightBillboard = GraphicsSystem.Global.CreateBillboard("Textures\\LightBulb");
            lightBillboard.Scale = new Vector2(1, 1);

            GraphicsNode lightn = new GraphicsNode(scene);
            lightn.Position = new Vector3(30, 9, 30);
            lightn.VisualObjects.Add(light);
            lightn.VisualObjects.Add(lightBillboard);
            scene.RootNode.ChildNodes.Add(lightn);

            PhysicsTestNode ball = new PhysicsTestNode(scene);
            ModelInstance ballModel = GraphicsSystem.Global.CreateModelInstance("Models\\box20x40x150");
            ball.SetModel(ballModel);
            scene.RootNode.ChildNodes.Add(ball);

            /*ModelInstance lm = GraphicsSystem.Global.CreateModelInstance("Models\\Sphere");
            lm.Model.SetSingleMaterial(new Material());
            lightn.VisualObjects.Add(lm);*/

            //for (int i = 0; i < 4; ++i)
            //{
            //    for (int j = 0; j < 4; ++j)
            //    {
            //        GraphicsNode lightNode = new GraphicsNode(mScene);
            //        lightNode.Position = new Vector3(5500 * i, 600, 5500 * j);

            //        SceneVisualObject lightModel = GraphicsSystem.Global.CreateModelObject("Models\\Sphere");
            //        lightModel.AsModelObject().SetSingleMaterial(new Material());
            //        lightNode.VisualObjects.Add(lightModel);



            //        SceneVisualObject light2;
            //        light2 = GraphicsSystem.Global.CreateLight(LightType.POINT);
            //        light2.AsLight().Range = 2000;
            //        light2.AsLight().Strength =0.5f;
            //        lightNode.VisualObjects.Add(light2);

            //        mScene.RootNode.ChildNodes.Add(lightNode);
            //    }
            //}

            for (int i = 0; i < 12; ++i)
            {
                for (int j = 0; j < 12; ++j)
                {
                    ModelInstance model3 = GraphicsSystem.Global.CreateModelInstance("Models\\plane");

                    node = new GraphicsNode(scene);
                    node.Position = new Vector3(i * 15, -2, j * 15);
                    node.Scale = new Vector3(1.905f);
                    node.VisualObjects.Add(model3);
                    scene.RootNode.ChildNodes.Add(node);
                }
            }

            //ModelInstance fountainModel = GraphicsSystem.Global.CreateModelInstance("Models\\Fountain");
            //node = new GraphicsNode(scene);
            //node.Position = new Vector3(3600, -200, 3600);
            //node.Scale = new Vector3(20.0f);
            //node.VisualObjects.Add(fountainModel);
            //scene.RootNode.ChildNodes.Add(node);

            PlayerNode player;
            if (isServer)
            {
                player = new PlayerNode(scene, null, true, false, new ServerPlayerNetComp());
            }
            else
            {
                player = new PlayerNode(scene, GraphicsSystem.Global.CreateModelInstance("Models\\Fountain"), false, true, new ClientPlayerNetComp(0));
            }
            player.Position = new Vector3(36, -2, 36);
            scene.RootNode.ChildNodes.Add(player);
            scene._localPlayer = player;


            //    lightNode_1 = new SceneNode(mScene);
            //    lightNode_1.Position = new Vector3(10000, 2000, 10000);

            //    ModelObject lightModel = new ModelObject("Models\\Sphere");
            //    lightModel.SetSingleMaterial(new Material());
            //    lightNode_1.AddSceneObject(lightModel);

            //    Light light = new Light(Light.LightType.POINT);
            //    lightNode_1.AddSceneObject(light);

            //    mScene.RootNode.ChildNodes.Add(lightNode_1);
            //}

            //node = new SceneNode(mScene);
            //node.AddSceneObject(new ModelObject("Models\\plane"));
            //mScene.RootNode.ChildNodes.Add(node);
            //{
            //    SceneNode lightNode = new SceneNode(mScene);
            //    lightNode.Position = Vector3.Zero;

            //    Light light = new Light(Light.LightType.DIRECTIONAL);
            //    light.BaseDirection = new Vector3(-1, 1, 1);
            //    lightNode.AddSceneObject(light);

            //    mScene.RootNode.ChildNodes.Add(lightNode);

            //}


            scene.Terrain = new Terrain("heightMap.png", new Vector3(1, 1, 1), content, device);
            scene.Terrain.WorldMatrix = Matrix.Identity;

            return scene;
        }
    }
}
